<template>
  <div class="point-basic">
    <h1>点</h1>
    <p>
      在WebGL中，点是最基本的图形元素。通过点的绘制，我们可以学习WebGL的基本渲染流程和顶点数据的处理方式。
    </p>

    <el-card class="demo-section">
      <template #header>
        <div class="card-header">
          <h3>点的绘制</h3>
        </div>
      </template>
      <div class="demo-content">
        <canvas ref="demoCanvas" width="400" height="300"></canvas>
        <div class="control-panel">
          <el-form :model="pointForm" label-width="100px">
            <el-form-item label="坐标 X">
              <el-slider
                v-model="pointForm.x"
                :min="-1"
                :max="1"
                :step="0.1"
                @input="updatePoint"
              />
            </el-form-item>
            <el-form-item label="坐标 Y">
              <el-slider
                v-model="pointForm.y"
                :min="-1"
                :max="1"
                :step="0.1"
                @input="updatePoint"
              />
            </el-form-item>
            <el-form-item label="点的大小">
              <el-slider v-model="pointForm.size" :min="1" :max="20" @input="updatePoint" />
            </el-form-item>
            <el-form-item label="点的颜色">
              <el-color-picker v-model="pointForm.color" @change="updatePoint" />
            </el-form-item>
          </el-form>
          <div class="position-info">当前位置: ({{ pointForm.x }}, {{ pointForm.y }})</div>
        </div>
      </div>
    </el-card>

    <el-card class="code-section">
      <template #header>
        <div class="card-header">
          <h3>示例代码</h3>
        </div>
      </template>
      <div class="code-content">
        <pre><code>
// 顶点着色器
attribute vec4 a_Position;
void main() {
  gl_Position = a_Position;
  gl_PointSize = 10.0;
}

// 片元着色器
precision mediump float;
uniform vec4 u_FragColor;
void main() {
  gl_FragColor = u_FragColor;
}

// JavaScript代码
const canvas = document.getElementById('webgl');
const gl = canvas.getContext('webgl');

// 创建着色器程序...

// 设置顶点位置
const vertices = new Float32Array([0.0, 0.0, 0.0]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);
        </code></pre>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { WebGLUtils, colorUtils } from '@/utils/webgl'

const demoCanvas = ref<HTMLCanvasElement | null>(null)
const gl = ref<WebGLRenderingContext | null>(null)
const shaderProgram = ref<WebGLProgram | null>(null)
const gridShaderProgram = ref<WebGLProgram | null>(null)
const webglUtils = ref<WebGLUtils | null>(null)

// 响应式数据
const pointForm = reactive({
  size: 10,
  color: '#409EFF',
  x: 0,
  y: 0,
})

// 初始化WebGL
const initWebGL = () => {
  if (!demoCanvas.value) return

  // 获取WebGL上下文
  gl.value = demoCanvas.value.getContext('webgl')
  if (!gl.value) {
    console.error('Failed to get WebGL context')
    return
  }

  // 创建WebGL工具实例
  webglUtils.value = new WebGLUtils(gl.value)

  // 顶点着色器源码
  const vertexShaderSource = `
    attribute vec4 a_Position;
    uniform float u_PointSize;
    void main() {
      gl_Position = a_Position;
      gl_PointSize = u_PointSize;
    }
  `

  // 片元着色器源码
  const fragmentShaderSource = `
    precision mediump float;
    uniform vec4 u_FragColor;
    void main() {
      gl_FragColor = u_FragColor;
    }
  `

  // 创建着色器
  const vertexShader = webglUtils.value.createShader(gl.value.VERTEX_SHADER, vertexShaderSource)
  const fragmentShader = webglUtils.value.createShader(
    gl.value.FRAGMENT_SHADER,
    fragmentShaderSource,
  )
  if (!vertexShader || !fragmentShader) return

  // 创建程序并链接着色器
  shaderProgram.value = webglUtils.value.createProgram(vertexShader, fragmentShader)
  if (!shaderProgram.value) return

  gl.value.useProgram(shaderProgram.value)

  // 初始化网格着色器程序
  const gridVertexShader = webglUtils.value.createShader(
    gl.value.VERTEX_SHADER,
    `
    attribute vec4 a_Position;
    void main() {
      gl_Position = a_Position;
    }
  `,
  )
  const gridFragmentShader = webglUtils.value.createShader(
    gl.value.FRAGMENT_SHADER,
    `
    precision mediump float;
    void main() {
      gl_FragColor = vec4(0.2, 0.2, 0.2, 0.2);
    }
  `,
  )
  if (!gridVertexShader || !gridFragmentShader) return

  gridShaderProgram.value = webglUtils.value.createProgram(gridVertexShader, gridFragmentShader)
  if (!gridShaderProgram.value) return

  // 设置顶点数据
  const vertices = new Float32Array([0.0, 0.0, 0.0])
  const vertexBuffer = webglUtils.value.createBuffer(vertices)
  if (!vertexBuffer) return

  // 设置顶点属性
  webglUtils.value.setVertexAttribute(shaderProgram.value, 'a_Position', 3)

  // 设置清除颜色并清除
  gl.value.clearColor(0.0, 0.0, 0.0, 1.0)
  gl.value.clear(gl.value.COLOR_BUFFER_BIT)

  // 绘制点
  updatePoint()
}

// 绘制网格
const drawGrid = () => {
  if (!gl.value || !gridShaderProgram.value || !webglUtils.value) return

  // 使用网格的着色器程序
  gl.value.useProgram(gridShaderProgram.value)

  const gridLines = []
  for (let i = -1; i <= 1; i += 0.2) {
    // 垂直线
    gridLines.push(i, -1, 0, i, 1, 0)
    // 水平线
    gridLines.push(-1, i, 0, 1, i, 0)
  }

  const vertices = new Float32Array(gridLines)
  const vertexBuffer = webglUtils.value.createBuffer(vertices)
  if (!vertexBuffer) return

  webglUtils.value.setVertexAttribute(gridShaderProgram.value, 'a_Position', 3)
  gl.value.drawArrays(gl.value.LINES, 0, gridLines.length / 3)
}

// 更新点的属性并重绘
const updatePoint = () => {
  if (!gl.value || !shaderProgram.value || !webglUtils.value) return

  gl.value.clear(gl.value.COLOR_BUFFER_BIT)

  // 先绘制网格
  drawGrid()

  // 切换回点的着色器程序
  gl.value.useProgram(shaderProgram.value)

  // 设置点的位置
  const vertices = new Float32Array([pointForm.x, pointForm.y, 0.0])
  const vertexBuffer = webglUtils.value.createBuffer(vertices)
  if (!vertexBuffer) return

  webglUtils.value.setVertexAttribute(shaderProgram.value, 'a_Position', 3)

  // 设置点的颜色
  const color = colorUtils.hexToRgb(pointForm.color)
  const u_FragColor = gl.value.getUniformLocation(shaderProgram.value, 'u_FragColor')
  gl.value.uniform4f(u_FragColor, color.r, color.g, color.b, 1.0)

  // 设置点的大小
  const u_PointSize = gl.value.getUniformLocation(shaderProgram.value, 'u_PointSize')
  gl.value.uniform1f(u_PointSize, pointForm.size)

  // 绘制点
  gl.value.drawArrays(gl.value.POINTS, 0, 1)
}

// 组件挂载时初始化WebGL
onMounted(() => {
  initWebGL()
})
</script>

<style lang="scss" scoped>
.point-basic {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;

  h1 {
    color: #303133;
    margin-bottom: 20px;
  }

  .demo-section,
  .code-section {
    margin: 30px 0;

    .card-header {
      display: flex;
      align-items: center;

      h3 {
        margin: 0;
        color: #409eff;
      }
    }
  }

  .demo-section {
    .demo-content {
      display: flex;
      gap: 20px;

      canvas {
        border: 1px solid #dcdfe6;
        background-color: #000;
      }

      .control-panel {
        flex: 1;
        padding: 20px;
        background-color: #f8f9fa;
        border-radius: 4px;
      }

      .position-info {
        margin-top: 20px;
        text-align: center;
        color: #606266;
        font-family: monospace;
      }
    }
  }

  .code-section {
    .code-content {
      background-color: #f8f9fa;
      padding: 15px;
      border-radius: 4px;

      code {
        font-family: monospace;
        color: #409eff;
      }

      pre {
        margin: 0;
        white-space: pre-wrap;
      }
    }
  }
}
</style>
